package edu.mse.camel.client.posterboard.ui.editpart;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPartFactory;
import org.eclipse.gef.editparts.AbstractConnectionEditPart;
import org.eclipse.uml2.uml.Element;

import com.cea.papyrus.diagraminterchange2.di2.Diagram;
import com.cea.papyrus.diagraminterchange2.di2.DiagramElement;

import edu.mse.camel.client.posterboard.posterboard.PBDiagram;
import edu.mse.camel.client.posterboard.posterboard.Posterboard;
import edu.mse.camel.client.posterboard.ui.adapters.IToolAdapter;
import edu.mse.camel.client.posterboard.ui.adapters.UMLToolAdapter;
import edu.mse.camel.client.posterboard.ui.adapters.WhiteboardAdapter;
import edu.mse.camel.client.posterboard.ui.editor.PosterBoardModelManager;
import edu.mse.camel.client.whiteboard.gef.ui.editpart.WhiteboardDiagramEditPart;
import edu.mse.camel.client.whiteboard.gef.whiteboard.FreeWritingShape;
import edu.mse.camel.client.whiteboard.gef.whiteboard.Shape;
import edu.mse.camel.client.whiteboard.gef.whiteboard.WhiteboardDiagram;

public class PosterBoardEditPartFactory implements EditPartFactory {

	private PosterBoardModelManager modelManager;
	private EditPartFactory delegate;
	private IToolAdapter adapter;
	
	public PosterBoardEditPartFactory(PosterBoardModelManager modelManager,
			IToolAdapter util) {
		this.modelManager = modelManager;
		this.adapter = util;
	}
	
	@Override
	public EditPart createEditPart(EditPart context, Object model) {
		// get EditPart for model element
		setAdapter(model);
		EditPart part = getPartForElement(model);
		if (part != null) {
			return part;
		} else {
			if (shouldSetDelegate(context)) {
				delegate = setDelegate(context);
			}
			return delegate.createEditPart(context, model);
		}
	}

	private void setAdapter(Object model) {
		if (model instanceof Element || model instanceof DiagramElement) {
			adapter = UMLToolAdapter.INSTANCE;
		} else if (model instanceof Shape || model instanceof FreeWritingShape) {
			adapter = WhiteboardAdapter.INSTANCE;
		}
	}

	private boolean shouldSetDelegate(EditPart context) {
		if (delegate == null) {
			return true;
		}
		// TODO: The next if check is a hack, not much is known about this
		// right now. Wil investigate later.
		if (context instanceof AbstractConnectionEditPart) {
			return false;
		}
		
		return adapter.shouldSetDelegate(context, delegate);
	}

	private EditPartFactory setDelegate(EditPart context) {
		return adapter.getEditPartFactory(context);
	}

	private void setDelegate(String diagramType) {
		delegate = adapter.getEditPartFactory(diagramType);
	}
	
	private EditPart getPartForElement(Object model) {
		if (model instanceof Posterboard) {
			PosterBoardEditpart part = new PosterBoardEditpart(
												(Posterboard) model, modelManager);
			return part;
		} else if (model instanceof PBDiagram) {
			setAdapter(((PBDiagram) model).getDelegate());
			return adapter.getAdaptedDiagramEditpart((PBDiagram) model);
		}
		return null;
	}

	private void setAdapter(EObject eObject) {
		if (eObject instanceof Diagram) {
			adapter = UMLToolAdapter.INSTANCE;
		} else if (eObject instanceof WhiteboardDiagram) {
			adapter = WhiteboardAdapter.INSTANCE;
		}
		
	}

	public void setAdapter(String diagramType) {
		if (UMLToolAdapter.INSTANCE.isSupported(diagramType)) {
			adapter = UMLToolAdapter.INSTANCE;
		}
		if (WhiteboardAdapter.INSTANCE.isSupported(diagramType)) {
			adapter = WhiteboardAdapter.INSTANCE;
		}
		setDelegate(diagramType);
	}

}
